package main

import (
	"database/sql"
	"fmt"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"net/http"
)

// 定义两个全局对象db
var localDb *sql.DB
var remoteDb *sql.DB

// 定义一个初始化数据库的函数
func initDB() (err error) {
	// DSN:Data Source Name
	dsn1 := "账号:密码@tcp(IP地址:3306)/test?charset=utf8mb4&parseTime=True"
	dsn2 := "账号:密码@tcp(IP地址:3306)/test?charset=utf8mb4&parseTime=True"
	// 不会校验账号密码是否正确
	// 注意！！！这里不要使用:=，我们是给全局变量赋值，然后在main函数中使用全局变量db
	localDb, err = sql.Open("mysql", dsn1)
	if err != nil {
		return err
	}
	remoteDb, err = sql.Open("mysql", dsn2)
	if err != nil {
		return err
	}
	// 尝试与数据库建立连接（校验dsn是否正确）
	err = localDb.Ping()
	if err != nil {
		return err
	}
	err = remoteDb.Ping()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	err := initDB() // 调用输出化数据库的函数
	if err != nil {
		fmt.Printf("init db failed,err:%v\n", err)
		return
	}

	r := gin.Default()

	//学生信息管理模块包括增加、删除、修改、查询等。
	//（1）当有新生入学或有学生转入时，需要将其基本信息，如姓名、学号、 所在院校、专业班级等录入到学生档案中。
	r.POST("/student", func(context *gin.Context) {
		// 获取姓名、学号、 所在院校、专业、班级和校区
		name := context.PostForm("name")
		sex := context.PostForm("sex")
		class := context.PostForm("class")
		sid := context.PostForm("sid")
		department := context.PostForm("department")
		major := context.PostForm("major")
		school := context.PostForm("school") // 0 代表本地，1 代表远程
		sql := "INSERT INTO `test`.`hubu_student`(`SID`, `Name`, `Sex`, `Class`, `Major`, `Department`) VALUES (?, ?, ?, ?, ?, ?);"
		if school == "0" {
			_, err := localDb.Exec(sql, sid, name, sex, class, major, department)
			show(context, err)
		} else {
			_, err := remoteDb.Exec(sql, sid, name, sex, class, major, department)
			show(context, err)
		}
	})

	//（2）当学生毕业或有学生退学时，学需将其基本信息从学生档案中删除。
	r.DELETE("/student", func(context *gin.Context) {
		sid := context.Query("sid")
		sqlStr1 := "delete from hubu_student where SID = ?"
		sqlStr2 := "delete from hubu_score where SID = ?"
		_, err := localDb.Exec(sqlStr1, sid)
		if err != nil {
			fmt.Printf("不在本地数据库:%v\n", err)
			_, err1 := remoteDb.Exec(sqlStr1, sid)
			if err1 != nil {
				fmt.Printf("也不在远程数据库:%v\n", err)
				context.JSON(http.StatusOK, gin.H{
					"message": "数据库中无此学生的信息",
				})
			} else {
				remoteDb.Exec(sqlStr2, sid)
				context.JSON(http.StatusOK, gin.H{
					"message": "删除成功",
				})
			}
		} else {
			localDb.Exec(sqlStr2, sid)
			context.JSON(http.StatusOK, gin.H{
				"message": "删除成功",
			})
		}
	})

	//（3）当有学生转专业时，需要将其基本信息进行修改。
	r.PUT("/student", func(context *gin.Context) {
		// 获取姓名、学号、 所在院校、专业、班级和校区
		name := context.PostForm("name")
		sex := context.PostForm("sex")
		class := context.PostForm("class")
		sid := context.PostForm("sid")
		department := context.PostForm("department")
		major := context.PostForm("major")
		school := context.PostForm("school") // 0 代表本地，1 代表远程
		sql := "UPDATE `test`.`hubu_student` set `Name` = ?, `Sex` = ?, `Class` = ?, `Major` = ?, `Department` = ? where `SID` = ?;"
		if school == "0" {
			_, err := localDb.Exec(sql, name, sex, class, major, department, sid)
			show(context, err)
		} else {
			_, err := remoteDb.Exec(sql, name, sex, class, major, department, sid)
			show(context, err)
		}
	})

	type stu struct {
		Sid        string `json:"sid"`
		Name       string `json:"name"`
		Sex        string `json:"sex"`
		Class      string `json:"class"`
		Major      string `json:"major"`
		Department string `json:"department"`
	}

	type stu1 struct {
		Sid        string `json:"sid"`
		Name       string `json:"name"`
		Sex        string `json:"sex"`
		Class      string `json:"class"`
		Major      string `json:"major"`
		Department string `json:"department"`
		School     int    `json:"school"`
	}

	//（4）当需要得到某个学生相关信息时就要进行查询。
	r.GET("/student", func(context *gin.Context) {
		sid := context.Query("sid") // 如果传进来的是0，就代表查询全部学生
		sqlStr1 := "select sid, `name`, sex, class, major, department from hubu_student"
		sqlStr2 := "select sid, `name`, sex, class, major, department from hubu_student where sid=?"
		var u stu
		var t stu1
		var stu1s []stu1
		//TODO 这里返回去的时候要加上校区
		if sid == "0" {
			rows, err := localDb.Query(sqlStr1)
			if err != nil {
				fmt.Printf("本地数据库没有:%v\n", err)
				return
			}
			defer rows.Close()

			for rows.Next() {
				err1 := rows.Scan(&u.Sid, &u.Name, &u.Sex, &u.Class, &u.Major, &u.Department)
				if err1 != nil {
					fmt.Printf("scan failed, err:%v\n", err1)
					return
				}
				t.Name = u.Name
				t.Class = u.Class
				t.Department = u.Department
				t.Major = u.Major
				t.Sex = u.Sex
				t.Sid = u.Sid
				t.School = 0
				stu1s = append(stu1s, t)
			}
			rows2, err := remoteDb.Query(sqlStr1)
			if err != nil {
				fmt.Printf("远程数据库没有:%v\n", err)
				return
			}
			defer rows2.Close()
			for rows2.Next() {
				err1 := rows2.Scan(&u.Sid, &u.Name, &u.Sex, &u.Class, &u.Major, &u.Department)
				if err1 != nil {
					fmt.Printf("scan failed, err:%v\n", err1)
					return
				}
				t.Name = u.Name
				t.Class = u.Class
				t.Department = u.Department
				t.Major = u.Major
				t.Sex = u.Sex
				t.Sid = u.Sid
				t.School = 1
				stu1s = append(stu1s, t)
			}
			context.JSON(http.StatusOK, stu1s)
		} else {
			var u stu
			// 非常重要：确保QueryRow之后调用Scan方法，否则持有的数据库链接不会被释放
			err := localDb.QueryRow(sqlStr2, sid).Scan(&u.Sid, &u.Name, &u.Sex, &u.Class, &u.Major, &u.Department)
			if err != nil {
				fmt.Printf("不在本地数据库:%v\n", err)
				err := remoteDb.QueryRow(sqlStr2, sid).Scan(&u.Sid, &u.Name, &u.Sex, &u.Class, &u.Major, &u.Department)
				if err != nil {
					fmt.Printf("不存在这个学生:%v\n", err)
					return
				}
				context.JSON(http.StatusOK, u)
				return
			}
			context.JSON(http.StatusOK, u)
		}
	})

	//成绩信息管理模块：
	//该模块主要是实现对学生成绩的录入查询工作，包括：
	type class struct {
		Cid  string `json:"cid"`
		Name string `json:"name"`
	}

	// 辅助接口：获取课程号代码
	r.GET("/cid", func(context *gin.Context) {
		sqlStr := "select CID, Name from hubu_course"
		var classes []class
		// 本地校区
		rows, err := localDb.Query(sqlStr)
		if err != nil {
			fmt.Printf("query failed, err:%v\n", err)
			return
		}
		// 非常重要：关闭rows释放持有的数据库链接
		defer rows.Close()

		// 循环读取结果集中的数据
		for rows.Next() {
			var u class
			err := rows.Scan(&u.Cid, &u.Name)
			if err != nil {
				fmt.Printf("scan failed, err:%v\n", err)
				return
			}
			classes = append(classes, u)
			fmt.Printf("cid:%d name:%s \n", u.Cid, u.Name)
		}
		context.JSON(http.StatusOK, classes)
	})

	//（1）学生成绩的录入
	r.POST("/score", func(context *gin.Context) {
		// 获取课程号、学号、 分数和校区
		cid := context.PostForm("cid")
		sid := context.PostForm("sid")
		score := context.PostForm("score")
		school := context.PostForm("school") // 0 代表本地，1 代表远程
		sql := "INSERT INTO `test`.`hubu_score`(`CID`, `SID`, `Score`) VALUES (?, ?, ?);"
		if school == "0" {
			_, err := localDb.Exec(sql, cid, sid, score)
			show(context, err)
		} else {
			_, err := remoteDb.Exec(sql, cid, sid, score)
			show(context, err)
		}
	})

	//（2）学生成绩查询
	type stuSCore struct {
		Name  string `json:"name"`
		Score int    `json:"score"`
	}

	r.GET("/score", func(context *gin.Context) {
		sid := context.Query("sid")
		school := context.Query("school")
		var scores []stuSCore
		sql := "SELECT `Name` name,Score score FROM hubu_score,hubu_course WHERE hubu_score.CID = hubu_course.CID AND SID = ?"
		if school == "0" {
			rows, err := localDb.Query(sql, sid)
			if err != nil {
				fmt.Printf("query failed, err:%v\n", err)
				return
			}
			// 非常重要：关闭rows释放持有的数据库链接
			defer rows.Close()

			// 循环读取结果集中的数据
			for rows.Next() {
				var u stuSCore
				err := rows.Scan(&u.Name, &u.Score)
				if err != nil {
					fmt.Printf("scan failed, err:%v\n", err)
					return
				}
				scores = append(scores, u)
				fmt.Printf("name:%d score:%s \n", u.Name, u.Score)
			}
		} else {
			rows, err := remoteDb.Query(sql, sid)
			if err != nil {
				fmt.Printf("query failed, err:%v\n", err)
				return
			}
			// 非常重要：关闭rows释放持有的数据库链接
			defer rows.Close()

			// 循环读取结果集中的数据
			for rows.Next() {
				var u stuSCore
				err := rows.Scan(&u.Name, &u.Score)
				if err != nil {
					fmt.Printf("scan failed, err:%v\n", err)
					return
				}
				scores = append(scores, u)
				fmt.Printf("name:%d score:%s \n", u.Name, u.Score)
			}
		}
		context.JSON(http.StatusOK, scores)
	})
	r.Run(":18888")
}

func show(context *gin.Context, err error) {
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		context.JSON(http.StatusInternalServerError, gin.H{
			"message": "insert failed",
		})
		return
	}
	context.JSON(http.StatusOK, gin.H{
		"message": "ok",
	})
}
